package cn.sola.redis;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;

import cn.sola.common.SpringJunitTest;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.ZParams;

/**
 * @author: kangxiaohui
 * @date：2017年12月11日 下午3:11:59
 * @version 1.0
 * 投票案例
 */
public class Chapter01  extends SpringJunitTest{
	private static final int ONE_WEEK_IN_SECONDS = 7 * 86400;
	private static final int VOTE_SCORE = 432;
	private static final int ARTICLES_PER_PAGE = 25;
	
	@Autowired
	private JedisPool jedisPool;
	
	@Test
	public void index(){
		System.out.println(jedisPool);
		//获取redis的实例
		System.out.println(jedisPool.getResource());
	}
	
	@Test
	public void run() {
		//Jedis conn = new Jedis("localhost");
		Jedis conn = jedisPool.getResource();
		conn.select(15);

		String articleId = postArticle(conn, "sola", "A title1", "http://www.google.com");
		System.out.println("We posted a new article with id: " + articleId);
		System.out.println("Its HASH looks like:");
		Map<String, String> articleData = conn.hgetAll("article:" + articleId);
		for (Map.Entry<String, String> entry : articleData.entrySet()) {
			System.out.println("  " + entry.getKey() + ": " + entry.getValue());
		}

		System.out.println();

		articleVote(conn, "other_user", "article:" + articleId);
		String votes = conn.hget("article:" + articleId, "votes");
		System.out.println("We voted for the article, it now has votes: " + votes);
		assert Integer.parseInt(votes) > 1;

		System.out.println("The currently highest-scoring articles are:");
		List<Map<String, String>> articles = getArticles(conn, 1);
		printArticles(articles);
		assert articles.size() >= 1;

		addGroups(conn, articleId, new String[] { "new-group" });
		System.out.println("We added the article to a new group, other articles include:");
		articles = getGroupArticles(conn, "new-group", 1);
		printArticles(articles);
		assert articles.size() >= 1;
	}

	//发布文章
	public String postArticle(Jedis conn, String user, String title, String link) {
		//文章id 自动增加
		String articleId = String.valueOf(conn.incr("article:"));

		String voted = "voted:" + articleId;
		//默认添加的时候,默认添加人投票
		conn.sadd(voted, user);
		conn.expire(voted, ONE_WEEK_IN_SECONDS);

		long now = System.currentTimeMillis() / 1000;
		String article = "article:" + articleId;
		HashMap<String, String> articleData = new HashMap<String, String>();
		articleData.put("title", title);
		articleData.put("link", link);
		articleData.put("user", user);
		articleData.put("now", String.valueOf(now));
		articleData.put("votes", "1");
		conn.hmset(article, articleData);
		//默认添加文章记录 时间 和分数 
		conn.zadd("score:", now + VOTE_SCORE, article);
		conn.zadd("time:", now, article);

		return articleId;
	}

	//文章投票
	public void articleVote(Jedis conn, String user, String article) {
		//文章是否过了投票日期
		long cutoff = (System.currentTimeMillis() / 1000) - ONE_WEEK_IN_SECONDS;
		if (conn.zscore("time:", article) < cutoff) {
			return;
		}

		String articleId = article.substring(article.indexOf(':') + 1);
		//用户是否投过票
		if (conn.sadd("voted:" + articleId, user) == 1) {
			conn.zincrby("score:", VOTE_SCORE, article);
			conn.hincrBy(article, "votes", 1l);
		}
	}

	public List<Map<String, String>> getArticles(Jedis conn, int page) {
		return getArticles(conn, page, "score:");
	}

	public List<Map<String, String>> getArticles(Jedis conn, int page, String order) {
		int start = (page - 1) * ARTICLES_PER_PAGE;
		int end = start + ARTICLES_PER_PAGE - 1;
		//获的前25的文章id
		Set<String> ids = conn.zrevrange(order, start, end);
		List<Map<String, String>> articles = new ArrayList<Map<String, String>>();
		for (String id : ids) {
			//文章详细信息
			Map<String, String> articleData = conn.hgetAll(id);
			articleData.put("id", id);
			articles.add(articleData);
		}

		return articles;
	}

	public void addGroups(Jedis conn, String articleId, String[] toAdd) {
		String article = "article:" + articleId;
		for (String group : toAdd) {
			conn.sadd("group:" + group, article);
		}
	}

	public List<Map<String, String>> getGroupArticles(Jedis conn, String group, int page) {
		return getGroupArticles(conn, group, page, "score:");
	}

	public List<Map<String, String>> getGroupArticles(Jedis conn, String group, int page, String order) {
		String key = order + group;
		if (!conn.exists(key)) {
			ZParams params = new ZParams().aggregate(ZParams.Aggregate.MAX);
			conn.zinterstore(key, params, "group:" + group, order);
			conn.expire(key, 60);
		}
		return getArticles(conn, page, key);
	}

	//循环遍历输出文章详情
	private void printArticles(List<Map<String, String>> articles) {
		for (Map<String, String> article : articles) {
			System.out.println("  id: " + article.get("id"));
			for (Map.Entry<String, String> entry : article.entrySet()) {
				if (entry.getKey().equals("id")) {
					continue;
				}
				System.out.println("    " + entry.getKey() + ": " + entry.getValue());
			}
		}
	}
}
